home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Your Choice 3
/
Your Choice Software Collection 3.iso
/
prgmming
/
xlib41
/
pmio.inc
< prev
next >
Wrap
Text File
|
1994-03-01
|
33KB
|
735 lines
; Protected-Mode Input/Output Procedures.
; Version 1.1
;
; All PMIO procedures assume that the code is resident in a 32-bit segment.
;The flat-data model is also assumed, that is, DS = FLATDSEL. If the latter
;assumption is unacceptable, then modify the code to load DS at the beginning of
;the procedures. A full explanation of each IO procedure is provided above the
;procedure. The following is a brief summary:
;
;Screen Procedures:
;
; The screen procedures always print at the recorded BIOS cursor position and
;update the BIOS position after printing; however, they do not adjust the video
;hardware to actually relocate the cursor on the screen. Call UPDATECSR for
;this purpose.
; The screen procedures avoid all calls to DOS and BIOS. Therefore, they
;should function properly within interrupt handlers.
; The screen address is assumed to be B8000H, which will be the case for
;color monitors. For monochrome monitors, set SCRNBASEADR to B0000H.
;
;Procedure Description
;PCH Print ASCII character in AL
;CRLF Issue carriage return and line feed
;SCRLUP Scoll screen up
;SPC Print AL spaces
;CLS Clear screen
;PSTR Print zero terminated ASCII string at ES:EBX
;PCSSTR Print zero terminated ASCII string at CS:EBX
;PHW Print WORD in AX as hexadecimal
;PHD Print DWORD in EAX as hexadecimal
;PUW Print unsigned WORD in AX as decimal
;PUD Print unsigned DWORD in EAX as decimal
;PSW Print signed WORD in AX as decimal
;PSD Print signed DWORD in EAX as decimal
;FPST Print ST of FPU using format in AX. AH = characters to left of
; decimal. AL = characters to right of decimal.
;
;Keyboard Procedures:
;
;Procedure Description
;GETCH Get character from keyboard in AX. AL = either ASCII code or
; scan code. If sign bit of AH is set, then scan code. Other bits
; in AH define the state of shift and toggle keys (see procedure
; for detail). Character is not echoed.
;SETCSRPOS Set cursor position. Call with (AH,AL) = (row,column). Rows
; range from zero (top) to 24 (bottom). Columns range from zero
; (left) to 79 (right).
;GETCSRPOS Get cursor position in AX. (AH,AL) = (row,column).
;UPDATECSR Physically relocate cursor on screen to current BIOS coordinates.
;SETCSRTYPE Set cursor type. Call with AL = 0 for underline, or 1 for block.
; Call with sign bit of AL set to disable the cursor.
;SETCSR Set cursor position and type. Call with position in DX and type
; in CX. CH = start scan line, and CL = end scan line. Scan lines
; range from 0 (top) to 7 (bottom).
;GETCSR Get cursor position/type in DX/CX (CH/CL = start/end scan line).
;
;Speaker Procedures:
;
;Procedure Description
;BEEP Produce beep through speaker.
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;TASM Modifications
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; TASM users should set TASMMODE below to true. These modifications were
;tested with TASM 4.0.
TRUE = 1
FALSE = 0
TASMMODE = FALSE
IF TASMMODE
MASM51
QUIRKS
SMART
NOJUMPS
LARGESTACK
PUSHW MACRO IMMEDIATE16:REST ;PUSH immediate 16-bit data
IF (@WordSize EQ 4)
DB 66H
ENDIF
DB 68H
DW IMMEDIATE16
ENDM
PUSHD MACRO IMMEDIATE32:REST ;PUSH immediate 32-bit data
IF (@WordSize EQ 2)
DB 66H
ENDIF
DB 68H
DD IMMEDIATE32
ENDM
ENDIF
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;Local Data and Constants
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ALIGN 4
SCRNBASEADR DD 000B8000H ;Screen address
CURPOSADR EQU 00000450H ;BIOS address containing cursor position
TICKCNTADR EQU 0000046CH ;BIOS address containing timer-tick counter
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;Screen Routines
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;Print ASCII code in AL at cursor.
PCH PROC NEAR
PUSH EBX
PUSH EDX
MOV EDX,DWORD PTR DS:[CURPOSADR] ;Cursor (row,col) in (DH,DL)
PUSH EDX ;Push cursor position
XOR EBX,EBX
MOV BL,DH
SHL EBX,5 ;Multiply row by 160
LEA EBX,[EBX+4*EBX] ;160 = 32 + 4 * 32
AND EDX,0FFH ;Clear all but column
LEA EBX,[EBX+2*EDX]
ADD EBX,CS:SCRNBASEADR
POP EDX ;POP cursor position
MOV [EBX],AL
INC DL ;Increment column
CMP DL,79
JBE RCDCURSOR
XOR DL,DL ;Move to zero column of next row
INC DH ;Move to next row
RCDCURSOR: MOV WORD PTR DS:[CURPOSADR],DX ;Assume row is valid
CMP DH,24
JA DOSCROLL
EXIT: POP EDX
POP EBX
RET
DOSCROLL: PUSHD OFFSET EXIT
JMP SCRLUP
PCH ENDP
;Clear cursor to end of line and issue CRLF. Scroll up if necessary.
CRLF PROC NEAR
PUSH EAX
PUSH EBX
PUSH ECX
MOV EAX,DWORD PTR DS:[CURPOSADR]
PUSH EAX ;PUSH cursor position
XOR EBX,EBX
MOV BL,AH
SHL EBX,5 ;Multiply row by 160
LEA EBX,[EBX+4*EBX] ;160 = 32 + 4 * 32
AND EAX,0FFH ;Clear all but column
MOV CL,80
SUB CL,AL ;Get number of bytes to clear in CL
LEA EBX,[EBX+2*EAX]
ADD EBX,CS:SCRNBASEADR
MOV AL,32
CLREOL: MOV [EBX],AL ;Clear to end of line
ADD EBX,2
DEC CL
JNZ CLREOL
POP EAX ;POP cursor position
INC AH ;Increment row
CMP AH,24
JA DOSCROLL
XOR AL,AL ;Set column to zero
MOV WORD PTR DS:[CURPOSADR],AX
EXIT: POP ECX
POP EBX
POP EAX
RET
DOSCROLL: PUSHD OFFSET EXIT
JMP SCRLUP
CRLF ENDP
;Scroll entire screen up one line and leave cursor at start of line 24.
SCRLUP PROC NEAR
PUSH EAX
PUSH EBX
PUSH ECX
MOV EBX,CS:SCRNBASEADR
MOV ECX,960 ;960 = (80*24*2)/4 (DWORDS to scroll)
SCROLLLOOP: MOV EAX,[EBX+160]
MOV [EBX],EAX
ADD EBX,4
DEC ECX
JNZ SCROLLLOOP
MOV CL,80
MOV AL,32
CLR24: MOV [EBX],AL ;Clear line 24
ADD EBX,2
DEC CL
JNZ CLR24
EXIT: MOV WORD PTR DS:[CURPOSADR],1800H ;Set cursor to bottom line in zero column
POP ECX
POP EBX
POP EAX
RET
SCRLUP ENDP
;Print AL spaces at cursor.
SPC PROC NEAR
OR AL,AL
JZ EXIT
PUSH EAX
MOV AH,AL
MOV AL,32
PRINTSPC: CALL PCH
DEC AH
JNZ PRINTSPC
POP EAX
EXIT: RET
SPC ENDP
;Clear screen and leave cursor at (0,0) position.
CLS PROC NEAR
PUSH EAX
PUSH EBX
PUSH ESI
MOV EBX,CS:SCRNBASEADR
MOV ESI,1999
MOV AL,32
DOCLS: MOV [EBX+2*ESI],AL
DEC ESI
JNS DOCLS
MOV WORD PTR DS:[CURPOSADR],0H
POP ESI
POP EBX
POP EAX
RET
CLS ENDP
;Print ASCIIZ string at address in ES:EBX.
PSTR PROC NEAR
PUSH EAX
PUSH EBX
CHARLOOP: MOV AL,ES:[EBX]
OR AL,AL ;See if at end of string
JZ EXIT
CALL PCH
INC EBX
JMP CHARLOOP
EXIT: POP EBX
POP EAX
RET
PSTR ENDP
;Print ASCIIZ string at address CS:EBX.
PCSSTR PROC NEAR
PUSH EAX
PUSH EBX
CHARLOOP: MOV AL,CS:[EBX] ;See if at end of string
OR AL,AL
JZ EXIT
CALL PCH
INC EBX
JMP CHARLOOP
EXIT: POP EBX
POP EAX
RET
PCSSTR ENDP
;Print hexadecimal WORD in AX.
PHW PROC NEAR
PUSH EAX
PUSH ECX
PUSH EDX
MOV EDX,EAX
MOV CL,4 ;Print four nibbles
CALCNIBS: MOV AL,DL
AND AL,0FH
ADD AL,48
CMP AL,57
JBE PUSHDIGIT
ADD AL,7
PUSHDIGIT: PUSH EAX
SHR EDX,4
DEC CL
JNZ CALCNIBS
MOV CL,4
PRNTNIBS: POP EAX
CALL PCH
DEC CL
JNZ PRNTNIBS
POP EDX
POP ECX
POP EAX
RET
PHW ENDP
;Print hexadecimal DWORD in EAX.
PHD PROC NEAR
PUSH EAX
PUSH ECX
PUSH EDX
MOV EDX,EAX
MOV CL,8 ;Print eight nibbles
CALCNIBS: MOV AL,DL
AND AL,0FH
ADD AL,48
CMP AL,57
JBE PUSHDIGIT
ADD AL,7
PUSHDIGIT: PUSH EAX
SHR EDX,4
DEC CL
JNZ CALCNIBS
MOV CL,8
PRNTNIBS: POP EAX
CALL PCH
DEC CL
JNZ PRNTNIBS
POP EDX
POP ECX
POP EAX
RET
PHD ENDP
;Print unsigned WORD in AX as decimal.
PUW PROC NEAR
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
AND EAX,0FFFFH
XOR ECX,ECX
MOV EBX,10
CALCDIGS: XOR EDX,EDX
DIV BX
PUSH EDX
INC ECX
OR EAX,EAX
JNZ CALCDIGS
PRNTDIGS: POP EAX
ADD AL,48
CALL PCH
DEC ECX
JNZ PRNTDIGS
POP EDX
POP ECX
POP EBX
POP EAX
RET
PUW ENDP
;Print unsigned DWORD in EAX as decimal.
PUD PROC NEAR
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
XOR ECX,ECX
MOV EBX,10
CALCDIGS: XOR EDX,EDX
DIV EBX
PUSH EDX
INC ECX
OR EAX,EAX
JNZ CALCDIGS
PRNTDIGS: POP EAX
ADD AL,48
CALL PCH
DEC ECX
JNZ PRNTDIGS
POP EDX
POP ECX
POP EBX
POP EAX
RET
PUD ENDP
;Print signed WORD in AX as decimal.
PSW PROC NEAR
PUSH EAX
OR AX,AX
JNS PABS
PUSH EAX
MOV AL,"-"
CALL PCH
POP EAX
NEG AX ;Calculate absolute value
PABS: CALL PUW ;Print absolute value
POP EAX
RET
PSW ENDP
;Print signed DWORD in EAX as decimal.
PSD PROC NEAR
PUSH EAX
OR EAX,EAX
JNS PABS
PUSH EAX
MOV AL,"-"
CALL PCH
POP EAX
NEG EAX ;Calculate absolute value
PABS: CALL PUD ;Print absolute value
POP EAX
RET
PSD ENDP
;Print ST of FPU using format code in AX. Call with lowest seven bits of AH =
;number of high-order digits plus the sign (if negative), and lowest five bits
;of AL = number of low-order digits. Fractions are printed with leading zeros
;if the sign bit of AH is clear. Will print numbers absolutely smaller than
;10 ^ 18 and will print up to 18 decimal places. Will fill entire print field
;with "*" if high-order digit field is too small. Will fill entire print field
;with ">" if number is absolutely greater than or equal to 10 ^ 18. It is
;assumed that ST contains a valid number. AL must not be greater than 18.
FPST PROC NEAR
LOCAL NOLEAD0FLAG:DWORD ;If set, then no leading zero is placed in front of fractions
LOCAL FLDWIDTH:DWORD ;The width of the print field
LOCAL NOHIDIGITS:DWORD ;Number of high-order digits
LOCAL NOLODIGITS:DWORD ;Number of low-order digits
LOCAL OLDCWORD:WORD ;Old FPU control word
LOCAL NEWCWORD:WORD ;Local FPU control word
LOCAL HIDIGITS[10]:BYTE ;Storage for high-order digit string
LOCAL LODIGITS[10]:BYTE ;Storage for low-order digit string
PUSH EAX
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
XOR ECX,ECX ;Assume leading zeros on fractions
CHKLEADZERO: OR AH,AH ;Test assumption
JNS SETLEAD0MODE
INC ECX ;Will not print leading zeros
SETLEAD0MODE: MOV NOLEAD0FLAG,ECX
AND AH,7FH ;Mask leading zero flag
MOV CL,AH ;Set ECX = number of high order digits + sign
MOV NOHIDIGITS,ECX
MOV CL,AL ;Set ECX = number of decimal places
MOV NOLODIGITS,ECX
ADD AL,AH ;Compute field width in EAX
AND EAX,0FFH
OR ECX,ECX
JZ SETFLDWIDTH
INC EAX ;Account for decimal point
SETFLDWIDTH: MOV FLDWIDTH,EAX
FSTCW OLDCWORD ;Save original control word
MOV AX,OLDCWORD
OR AH,0FH ;Set PC to 64 bits and RC to truncate
MOV NEWCWORD,AX
FLDCW NEWCWORD
FLD ST ;See if number of high order digits greater than 18
FABS
FCOM CS:FPPOWERTEN[8*18]
FSTSW AX
SAHF
JAE OVERFLOW
FLD ST(1) ;Compute and save high order digits
FBSTP TBYTE PTR HIDIGITS[0]
FLD ST ;Compute and save low order digits
FRNDINT
AND BYTE PTR NEWCWORD[1],0F3H ;Set RC to round
FLDCW NEWCWORD
FSUB
FMUL CS:FPPOWERTEN[8*ECX]
CALCLODIGITS: XOR EAX,EAX
XOR EDI,EDI
MOV ESI,8
FBSTP TBYTE PTR LODIGITS[0]
GETHIDIGIT: OR AL,HIDIGITS[ESI] ;Find first nonzero digit
JNZ CALCHIORDER
DEC ESI
JNS GETHIDIGIT
XOR ESI,ESI ;There are no nonzero high order digits
TEST BYTE PTR NOLEAD0FLAG[0],01H ;See if leading zeros are disabled
JNZ CHKSIGN
INC ESI ;Add leading zero
JMP CHKSIGN
CALCHIORDER: MOV EDI,ESI
INC ESI ;Convert ESI to number of high order digits
ADD ESI,ESI
AND AL,0F0H ;See if highest digit is in odd position
JNZ CHKSIGN
DEC ESI
CHKSIGN: MOV DL,HIDIGITS[9] ;Get sign byte
OR DL,DL
JNS CHKHIFLD
INC ESI ;Account for "-"
CHKHIFLD: MOV EAX,NOHIDIGITS
SUB EAX,ESI ;See if field for high-order digits and sign is large enough
JB SMALLFLD
CALL SPC ;Print leading spaces
PRNTSIGN: OR DL,DL
JNS PRNTHIDIGITS
MOV AL,"-"
CALL PCH
DEC ESI
PRNTHIDIGITS: OR ESI,ESI ;See if any high order digits are to be printed
JZ PRNTDEC
MOV DL,HIDIGITS[EDI]
TEST ESI,01H
JNZ ODDHIDIGIT
HIDIGITLOOP: MOV AL,DL
SHR AL,4
ADD AL,48
CALL PCH
ODDHIDIGIT: MOV AL,DL
AND AL,0FH
ADD AL,48
CALL PCH
DEC EDI
JS PRNTDEC
MOV DL,HIDIGITS[EDI]
JMP HIDIGITLOOP
PRNTDEC: OR ECX,ECX ;See if any low order digits are to be printed
JZ EXIT
MOV AL,"."
CALL PCH
MOV EDI,ECX ;Find byte number for first digit
DEC EDI
SHR EDI,1
MOV DL,LODIGITS[EDI]
TEST CL,01H
JNZ ODDLODIGIT
LODIGITLOOP: MOV AL,DL
SHR AL,4
ADD AL,48
CALL PCH
ODDLODIGIT: MOV AL,DL
AND AL,0FH
ADD AL,48
CALL PCH
DEC EDI
JS EXIT
MOV DL,LODIGITS[EDI]
JMP LODIGITLOOP
EXIT: FLDCW OLDCWORD ;Restore calling control word
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
POP EAX
RET
FILLFLD: MOV ECX,FLDWIDTH
RCDCHAR: CALL PCH ;Print one character even if field width is zero
SUB ECX,1
JAE RCDCHAR
JMP EXIT
SMALLFLD: MOV AL,"*"
JMP FILLFLD
OVERFLOW: FSTP ST ;Pop absolute value of number
MOV AL,">"
JMP FILLFLD
ALIGN 8
FPPOWERTEN LABEL QWORD
DQ 1.0E0
DQ 1.0E1
DQ 1.0E2
DQ 1.0E3
DQ 1.0E4
DQ 1.0E5
DQ 1.0E6
DQ 1.0E7
DQ 1.0E8
DQ 1.0E9
DQ 1.0E10
DQ 1.0E11
DQ 1.0E12
DQ 1.0E13
DQ 1.0E14
DQ 1.0E15
DQ 1.0E16
DQ 1.0E17
DQ 1.0E18
FPST ENDP
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;Keyboard Routines
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;Get chracter from keyboard without echo. Return ASCII code or scan code in AL.
;The sign bit of AH is set if a scan code. The state of the shift keys is also
;in AH. Bits of AH are defined: 0 = shift, 1 = ctrl, 2 = alt, 3 = scroll lock,
;4 = num lock, 5 = caps lock, 6 = insert. The high word of EAX is cleared.
;Interrupts must be enabled.
GETCH PROC NEAR
PUSH EDX
MOV AH,10H ;Remove key from type-ahead buffer. Will wait if no key present
INT 16H ;Scan code in AH, ASCII code in AL
MOV EDX,EAX
MOV AH,12H ;Get state of flags
INT 16H
TEST AL,01H ;Combine right and left shift keys
JZ FIXFLAGS
OR AL,02H
FIXFLAGS: SHR AL,1
AND EAX,07FH
MOV AH,AL
MOV AL,DL ;Put ASCII scan code in AL
CMP AL,0E0H ;See if the character is for non-ASCII enhanced keyboard key
JE DOSCAN
OR AL,AL ;See if the character is for a non-ASCII key
JNZ EXIT
DOSCAN: MOV AL,DH ;Put scan code in AL
OR AH,80H ;Set high bit to denote scan code
EXIT: POP EDX
RET
GETCH ENDP
;Set cursor position at (row,col) = (AH,AL).
SETCSRPOS PROC NEAR
PUSH EAX
PUSH EBX
PUSH EDX
CMP AH,24 ;Do not allow row greater than 24
JBE CHKCOL
MOV AH,24
CHKCOL: CMP AL,79 ;Do not allow column greater than 79
JBE SETCURSOR
MOV AL,79
SETCURSOR: MOV EDX,EAX ;Place coordinates in DX
XOR EBX,EBX ;Use screen zero
MOV AH,02H ;Function to set cursor position
INT 10H
POP EDX
POP EBX
POP EAX
RET
SETCSRPOS ENDP
;Get cursor position in (AH,AL) = (row,col)
GETCSRPOS PROC NEAR
PUSH EBX
PUSH ECX
PUSH EDX
MOV AH,03H ;Function to get cursor position
XOR EBX,EBX ;Get position for screen zero
INT 10H ;Cursor position returned in DX, and type returned in CX
MOV EAX,EDX
POP EDX
POP ECX
POP EBX
RET
GETCSRPOS ENDP
;Physically relocate the cursor on the screen to the current BIOS coordinates.
UPDATECSR PROC NEAR
PUSHD OFFSET SETCSRPOS
JMP GETCSRPOS
UPDATECSR ENDP
;Set cursor type. Call with AL = 1 for block, AL = 0 for underline, and sign
;bit of AL set to disable.
SETCSRTYPE PROC NEAR
PUSH EAX
PUSH ECX
MOV AH,01H
MOV CX,0607H ;Assume underline cursor
OR AL,AL
JZ SETCURLINES
JS DISABLECSR
XOR CH,CH ;Set to block cursor
JMP SETCURLINES
DISABLECSR: MOV CH,20H ;Disable cursor
SETCURLINES: INT 10H
POP ECX
POP EAX
RET
SETCSRTYPE ENDP
;Get cursor position and type. Position in DX and type in CX.
GETCSR PROC NEAR
PUSH EAX
PUSH EBX
MOV AH,03H ;Function to get cursor position
XOR EBX,EBX ;BH = page
INT 10H ;(start,end) scan line for cursor in (CH,CL)
POP EBX ;(row/column) for cursor in (DH,DL)
POP EAX
RET
GETCSR ENDP
;Set cursor position and type. Call with (DH,DL) = (row,col) for cursor and
;(CH,CL) = (start,end) scan line for cursor.
SETCSR PROC NEAR
PUSH EAX
PUSH EBX
MOV AH,02H ;Set cursor position
XOR EBX,EBX ;Use page zero
INT 10H
DEC AH ;Set cursor type
INT 10H
POP EBX
POP EAX
RET
SETCSR ENDP
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;Speaker Routines
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;Produce beep through speaker. Interrupts must be enabled.
BEEP PROC NEAR
PUSH EAX
PUSH EDX
IN AL,61H
MOV DX,6818 ;175 cycles/second
CALL SOUND
MOV EDX,TICKCNTADR ;Hold sound for four ticks
PUSH EAX
MOV EAX,[EDX]
ADD EAX,4
DELAY: CMP [EDX],EAX ;Will hang in this loop timer-tick interrupt not enabled
JNE DELAY
POP EAX ;Disable sound
OUT 61H,AL
POP EDX
POP EAX
RET
BEEP ENDP
;Activate speaker. Call with frequency divisor in DX. Divisor = 1,193,180
;divided by cycles per second.
SOUND PROC NEAR
PUSH EAX
MOV AL,10110110B ;Channel 2, LSB/MSB, mode 3, binary
OUT 43H,AL ;Program the timer
MOV EAX,EDX
OUT 42H,AL
MOV AL,AH
OUT 42H,AL
IN AL,61H
OR AL,03H ;Enable speaker and use channel 2 for input
OUT 61H,AL
POP EAX
RET
SOUND ENDP